from abc import ABC, abstractmethod
from typing import Dict, Any, Optional
import yaml
import json
import logging
from jinja2 import Environment, FileSystemLoader
import os
import pandas as pd
import xml.etree.ElementTree as ET
from xml.dom import minidom
from tabulate import tabulate
import csv
from datetime import datetime
import matplotlib.pyplot as plt
import seaborn as sns
from tqdm import tqdm
import jsonlines
import pdfkit
import time
import openpyxl

logger = logging.getLogger(__name__)

class ReportFormatter(ABC):
    """报告格式化器基类"""
    
    def __init__(self, next_formatter: Optional['ReportFormatter'] = None):
        self.next_formatter = next_formatter
    
    def set_next(self, formatter: 'ReportFormatter') -> 'ReportFormatter':
        """设置下一个格式化器"""
        self.next_formatter = formatter
        return formatter
    
    @abstractmethod
    def can_handle(self, format_type: str) -> bool:
        """检查是否可以处理指定的格式"""
        pass
    
    @abstractmethod
    def format(self, data: Dict[str, Any], output_path: str) -> bool:
        """格式化数据并输出到指定路径"""
        pass
    
    def handle(self, data: Dict[str, Any], format_type: str, output_path: str) -> bool:
        """处理格式化请求"""
        if self.can_handle(format_type):
            return self.format(data, output_path)
        elif self.next_formatter:
            return self.next_formatter.handle(data, format_type, output_path)
        return False

class YAMLFormatter(ReportFormatter):
    """YAML格式报告格式化器"""
    
    def can_handle(self, format_type: str) -> bool:
        return format_type.lower() in ['yaml', 'yml']
    
    def format(self, data: Dict[str, Any], output_path: str) -> bool:
        try:
            with open(output_path, 'w', encoding='utf-8') as f:
                yaml.dump(data, f, allow_unicode=True, sort_keys=False)
            logger.info(f"YAML report exported to {output_path}")
            return True
        except Exception as e:
            logger.error(f"Error exporting YAML report: {str(e)}")
            return False

class JSONFormatter(ReportFormatter):
    """JSON格式报告格式化器"""
    
    def can_handle(self, format_type: str) -> bool:
        return format_type.lower() == 'json'
    
    def format(self, data: Dict[str, Any], output_path: str) -> bool:
        try:
            with open(output_path, 'w', encoding='utf-8') as f:
                json.dump(data, f, ensure_ascii=False, indent=2)
            logger.info(f"JSON report exported to {output_path}")
            return True
        except Exception as e:
            logger.error(f"Error exporting JSON report: {str(e)}")
            return False

class HTMLFormatter(ReportFormatter):
    """HTML格式报告格式化器"""
    
    def __init__(self, template_dir: str, next_formatter: Optional[ReportFormatter] = None):
        super().__init__(next_formatter)
        self.env = Environment(loader=FileSystemLoader(template_dir))
    
    def can_handle(self, format_type: str) -> bool:
        return format_type.lower() == 'html'
    
    def format(self, data: Dict[str, Any], output_path: str) -> bool:
        try:
            template = self.env.get_template('health_report.html')
            html_content = template.render(
                summary=data['summary'],
                details=data['details'],
                title="Kubernetes Resource Health Report"
            )
            
            with open(output_path, 'w', encoding='utf-8') as f:
                f.write(html_content)
            
            logger.info(f"HTML report exported to {output_path}")
            return True
        except Exception as e:
            logger.error(f"Error exporting HTML report: {str(e)}")
            return False

class PDFFormatter(ReportFormatter):
    """PDF格式报告格式化器"""
    
    def __init__(self, template_dir: str, next_formatter: Optional[ReportFormatter] = None):
        super().__init__(next_formatter)
        self.env = Environment(loader=FileSystemLoader(template_dir))
    
    def can_handle(self, format_type: str) -> bool:
        return format_type.lower() == 'pdf'
    
    def format(self, data: Dict[str, Any], output_path: str) -> bool:
        try:
            # 首先生成HTML
            template = self.env.get_template('health_report.html')
            html_content = template.render(
                summary=data['summary'],
                details=data['details'],
                title="Kubernetes Resource Health Report"
            )
            
            # 创建临时HTML文件
            temp_html = f"{output_path}.temp.html"
            with open(temp_html, 'w', encoding='utf-8') as f:
                f.write(html_content)
            
            # 转换为PDF
            pdfkit.from_file(temp_html, output_path)
            
            # 删除临时文件
            os.remove(temp_html)
            
            logger.info(f"PDF report exported to {output_path}")
            return True
        except Exception as e:
            logger.error(f"Error exporting PDF report: {str(e)}")
            return False

class MarkdownFormatter(ReportFormatter):
    """Markdown格式报告格式化器"""
    
    def can_handle(self, format_type: str) -> bool:
        return format_type.lower() in ['md', 'markdown']
    
    def format(self, data: Dict[str, Any], output_path: str) -> bool:
        try:
            content = []
            
            # 添加标题
            content.append("# Kubernetes Resource Health Report\n")
            
            # 添加摘要
            content.append("## Summary\n")
            summary = data['summary']
            content.append(f"- Total Resources: {summary['total_resources']}")
            content.append(f"- Healthy: {summary['healthy']}")
            content.append(f"- Warning: {summary['warning']}")
            content.append(f"- Critical: {summary['critical']}")
            content.append(f"- Unknown: {summary['unknown']}")
            content.append(f"- Average Score: {summary['average_score']:.2f}\n")
            
            # 添加详细信息
            content.append("## Details\n")
            for resource_id, result in data['details'].items():
                content.append(f"### {resource_id}\n")
                content.append(f"- Status: {result['status']}")
                content.append(f"- Score: {result['score']}")
                content.append(f"- Message: {result['message']}")
                
                if result['issues']:
                    content.append("\n#### Issues:")
                    for issue in result['issues']:
                        content.append(f"- {issue}")
                
                if result['suggestions']:
                    content.append("\n#### Suggestions:")
                    for suggestion in result['suggestions']:
                        content.append(f"- {suggestion}")
                
                content.append("\n")
            
            with open(output_path, 'w', encoding='utf-8') as f:
                f.write('\n'.join(content))
            
            logger.info(f"Markdown report exported to {output_path}")
            return True
        except Exception as e:
            logger.error(f"Error exporting Markdown report: {str(e)}")
            return False

class ExcelFormatter(ReportFormatter):
    """Excel格式报告格式化器"""
    
    def can_handle(self, format_type: str) -> bool:
        return format_type.lower() in ['excel', 'xlsx']
    
    def format(self, data: Dict[str, Any], output_path: str) -> bool:
        try:
            # 创建Excel写入器
            with pd.ExcelWriter(output_path, engine='openpyxl') as writer:
                # 创建摘要sheet
                summary_data = {
                    'Metric': ['Total Resources', 'Healthy', 'Warning', 'Critical', 'Unknown', 'Average Score'],
                    'Value': [
                        data['summary']['total_resources'],
                        data['summary']['healthy'],
                        data['summary']['warning'],
                        data['summary']['critical'],
                        data['summary']['unknown'],
                        f"{data['summary']['average_score']:.2f}"
                    ]
                }
                pd.DataFrame(summary_data).to_excel(writer, sheet_name='Summary', index=False)
                
                # 创建详细信息sheet
                details_data = []
                for resource_id, result in data['details'].items():
                    details_data.append({
                        'Resource ID': resource_id,
                        'Status': result['status'],
                        'Score': result['score'],
                        'Message': result['message'],
                        'Issues': '\n'.join(result['issues']) if result['issues'] else '',
                        'Suggestions': '\n'.join(result['suggestions']) if result['suggestions'] else ''
                    })
                pd.DataFrame(details_data).to_excel(writer, sheet_name='Details', index=False)
                
                # 设置列宽
                for sheet_name in writer.sheets:
                    worksheet = writer.sheets[sheet_name]
                    for idx, col in enumerate(worksheet.columns):
                        max_length = max(
                            len(str(cell.value)) for cell in col
                        )
                        worksheet.column_dimensions[chr(65 + idx)].width = min(max_length + 2, 50)
            
            logger.info(f"Excel report exported to {output_path}")
            return True
        except Exception as e:
            logger.error(f"Error exporting Excel report: {str(e)}")
            return False

class CSVFormatter(ReportFormatter):
    """CSV格式报告格式化器"""
    
    def can_handle(self, format_type: str) -> bool:
        return format_type.lower() == 'csv'
    
    def format(self, data: Dict[str, Any], output_path: str) -> bool:
        try:
            # 创建CSV文件
            with open(output_path, 'w', newline='', encoding='utf-8') as f:
                writer = csv.writer(f)
                
                # 写入摘要
                writer.writerow(['Summary'])
                writer.writerow(['Metric', 'Value'])
                writer.writerow(['Total Resources', data['summary']['total_resources']])
                writer.writerow(['Healthy', data['summary']['healthy']])
                writer.writerow(['Warning', data['summary']['warning']])
                writer.writerow(['Critical', data['summary']['critical']])
                writer.writerow(['Unknown', data['summary']['unknown']])
                writer.writerow(['Average Score', f"{data['summary']['average_score']:.2f}"])
                writer.writerow([])  # 空行
                
                # 写入详细信息
                writer.writerow(['Details'])
                writer.writerow(['Resource ID', 'Status', 'Score', 'Message', 'Issues', 'Suggestions'])
                for resource_id, result in data['details'].items():
                    writer.writerow([
                        resource_id,
                        result['status'],
                        result['score'],
                        result['message'],
                        '; '.join(result['issues']) if result['issues'] else '',
                        '; '.join(result['suggestions']) if result['suggestions'] else ''
                    ])
            
            logger.info(f"CSV report exported to {output_path}")
            return True
        except Exception as e:
            logger.error(f"Error exporting CSV report: {str(e)}")
            return False

class XMLFormatter(ReportFormatter):
    """XML格式报告格式化器"""
    
    def can_handle(self, format_type: str) -> bool:
        return format_type.lower() == 'xml'
    
    def format(self, data: Dict[str, Any], output_path: str) -> bool:
        try:
            # 创建根元素
            root = ET.Element('HealthReport')
            root.set('timestamp', datetime.now().isoformat())
            
            # 添加摘要
            summary = ET.SubElement(root, 'Summary')
            for key, value in data['summary'].items():
                item = ET.SubElement(summary, key)
                item.text = str(value)
            
            # 添加详细信息
            details = ET.SubElement(root, 'Details')
            for resource_id, result in data['details'].items():
                resource = ET.SubElement(details, 'Resource')
                resource.set('id', resource_id)
                
                status = ET.SubElement(resource, 'Status')
                status.text = result['status']
                
                score = ET.SubElement(resource, 'Score')
                score.text = str(result['score'])
                
                message = ET.SubElement(resource, 'Message')
                message.text = result['message']
                
                if result['issues']:
                    issues = ET.SubElement(resource, 'Issues')
                    for issue in result['issues']:
                        item = ET.SubElement(issues, 'Issue')
                        item.text = issue
                
                if result['suggestions']:
                    suggestions = ET.SubElement(resource, 'Suggestions')
                    for suggestion in result['suggestions']:
                        item = ET.SubElement(suggestions, 'Suggestion')
                        item.text = suggestion
            
            # 格式化XML
            xml_str = minidom.parseString(ET.tostring(root)).toprettyxml(indent='  ')
            
            # 写入文件
            with open(output_path, 'w', encoding='utf-8') as f:
                f.write(xml_str)
            
            logger.info(f"XML report exported to {output_path}")
            return True
        except Exception as e:
            logger.error(f"Error exporting XML report: {str(e)}")
            return False

class ConsoleFormatter(ReportFormatter):
    """控制台输出格式化器"""
    
    def can_handle(self, format_type: str) -> bool:
        return format_type.lower() in ['console', 'cli']
    
    def format(self, data: Dict[str, Any], output_path: str) -> bool:
        try:
            content = []
            
            # 添加标题
            content.append("Kubernetes Resource Health Report")
            content.append("=" * 50)
            content.append("")
            
            # 添加摘要
            content.append("Summary:")
            content.append("-" * 20)
            summary = data['summary']
            summary_table = [
                ["Total Resources", summary['total_resources']],
                ["Healthy", summary['healthy']],
                ["Warning", summary['warning']],
                ["Critical", summary['critical']],
                ["Unknown", summary['unknown']],
                ["Average Score", f"{summary['average_score']:.2f}"]
            ]
            content.append(tabulate(summary_table, tablefmt="grid"))
            content.append("")
            
            # 添加详细信息
            content.append("Details:")
            content.append("-" * 20)
            for resource_id, result in data['details']:
                content.append(f"\nResource: {resource_id}")
                content.append(f"Status: {result['status']}")
                content.append(f"Score: {result['score']}")
                content.append(f"Message: {result['message']}")
                
                if result['issues']:
                    content.append("\nIssues:")
                    for issue in result['issues']:
                        content.append(f"  - {issue}")
                
                if result['suggestions']:
                    content.append("\nSuggestions:")
                    for suggestion in result['suggestions']:
                        content.append(f"  - {suggestion}")
                
                content.append("-" * 50)
            
            # 写入文件
            with open(output_path, 'w', encoding='utf-8') as f:
                f.write('\n'.join(content))
            
            logger.info(f"Console report exported to {output_path}")
            return True
        except Exception as e:
            logger.error(f"Error exporting console report: {str(e)}")
            return False

class JUnitFormatter(ReportFormatter):
    """JUnit XML格式报告格式化器"""
    
    def can_handle(self, format_type: str) -> bool:
        return format_type.lower() in ['junit', 'junit-xml']
    
    def format(self, data: Dict[str, Any], output_path: str) -> bool:
        try:
            # 创建根元素
            root = ET.Element('testsuites')
            root.set('timestamp', datetime.now().isoformat())
            
            # 创建测试套件
            testsuite = ET.SubElement(root, 'testsuite')
            testsuite.set('name', 'Kubernetes Resource Health Check')
            testsuite.set('tests', str(data['summary']['total_resources']))
            testsuite.set('failures', str(data['summary']['critical'] + data['summary']['warning']))
            testsuite.set('errors', str(data['summary']['unknown']))
            
            # 添加测试用例
            for resource_id, result in data['details'].items():
                testcase = ET.SubElement(testsuite, 'testcase')
                testcase.set('name', resource_id)
                testcase.set('classname', 'ResourceHealth')
                
                # 添加系统输出
                system_out = ET.SubElement(testcase, 'system-out')
                system_out.text = f"Status: {result['status']}\nScore: {result['score']}\nMessage: {result['message']}"
                
                # 如果有问题，添加失败信息
                if result['issues']:
                    failure = ET.SubElement(testcase, 'failure')
                    failure.set('message', 'Resource has health issues')
                    failure.text = '\n'.join(result['issues'])
                
                # 如果有建议，添加系统错误
                if result['suggestions']:
                    system_err = ET.SubElement(testcase, 'system-err')
                    system_err.text = 'Suggestions:\n' + '\n'.join(result['suggestions'])
            
            # 格式化XML
            xml_str = minidom.parseString(ET.tostring(root)).toprettyxml(indent='  ')
            
            # 写入文件
            with open(output_path, 'w', encoding='utf-8') as f:
                f.write(xml_str)
            
            logger.info(f"JUnit XML report exported to {output_path}")
            return True
        except Exception as e:
            logger.error(f"Error exporting JUnit XML report: {str(e)}")
            return False

class JSONLinesFormatter(ReportFormatter):
    """JSON Lines格式报告格式化器"""
    
    def can_handle(self, format_type: str) -> bool:
        return format_type.lower() in ['jsonl', 'jsonlines']
    
    def format(self, data: Dict[str, Any], output_path: str) -> bool:
        try:
            with jsonlines.open(output_path, mode='w') as writer:
                # 写入摘要
                writer.write({
                    'type': 'summary',
                    'timestamp': datetime.now().isoformat(),
                    'data': data['summary']
                })
                
                # 写入详细信息
                for resource_id, result in data['details'].items():
                    writer.write({
                        'type': 'resource',
                        'resource_id': resource_id,
                        'data': result
                    })
            
            logger.info(f"JSON Lines report exported to {output_path}")
            return True
        except Exception as e:
            logger.error(f"Error exporting JSON Lines report: {str(e)}")
            return False

class AsciiDocFormatter(ReportFormatter):
    """AsciiDoc格式报告格式化器"""
    
    def can_handle(self, format_type: str) -> bool:
        return format_type.lower() in ['asciidoc', 'adoc']
    
    def format(self, data: Dict[str, Any], output_path: str) -> bool:
        try:
            content = []
            
            # 添加标题
            content.append("= Kubernetes Resource Health Report")
            content.append(f":toc: left")
            content.append(f":toclevels: 3")
            content.append(f":sectnums:")
            content.append("")
            
            # 添加摘要
            content.append("== Summary")
            content.append("")
            summary = data['summary']
            content.append("[cols=\"1,1\"]")
            content.append("|===")
            content.append("|Total Resources|" + str(summary['total_resources']))
            content.append("|Healthy|" + str(summary['healthy']))
            content.append("|Warning|" + str(summary['warning']))
            content.append("|Critical|" + str(summary['critical']))
            content.append("|Unknown|" + str(summary['unknown']))
            content.append("|Average Score|" + f"{summary['average_score']:.2f}")
            content.append("|===")
            content.append("")
            
            # 添加详细信息
            content.append("== Details")
            content.append("")
            for resource_id, result in data['details'].items():
                content.append(f"=== {resource_id}")
                content.append("")
                content.append(f"Status:: {result['status']}")
                content.append(f"Score:: {result['score']}")
                content.append(f"Message:: {result['message']}")
                content.append("")
                
                if result['issues']:
                    content.append("==== Issues")
                    content.append("")
                    for issue in result['issues']:
                        content.append(f"* {issue}")
                    content.append("")
                
                if result['suggestions']:
                    content.append("==== Suggestions")
                    content.append("")
                    for suggestion in result['suggestions']:
                        content.append(f"* {suggestion}")
                    content.append("")
            
            # 写入文件
            with open(output_path, 'w', encoding='utf-8') as f:
                f.write('\n'.join(content))
            
            logger.info(f"AsciiDoc report exported to {output_path}")
            return True
        except Exception as e:
            logger.error(f"Error exporting AsciiDoc report: {str(e)}")
            return False

class EnhancedExcelFormatter(ExcelFormatter):
    """增强的Excel格式报告格式化器"""
    
    def format(self, data: Dict[str, Any], output_path: str) -> bool:
        try:
            # 创建Excel写入器
            with pd.ExcelWriter(output_path, engine='openpyxl') as writer:
                # 创建摘要sheet
                summary_data = {
                    'Metric': ['Total Resources', 'Healthy', 'Warning', 'Critical', 'Unknown', 'Average Score'],
                    'Value': [
                        data['summary']['total_resources'],
                        data['summary']['healthy'],
                        data['summary']['warning'],
                        data['summary']['critical'],
                        data['summary']['unknown'],
                        f"{data['summary']['average_score']:.2f}"
                    ]
                }
                summary_df = pd.DataFrame(summary_data)
                summary_df.to_excel(writer, sheet_name='Summary', index=False)
                
                # 创建详细信息sheet
                details_data = []
                for resource_id, result in data['details'].items():
                    details_data.append({
                        'Resource ID': resource_id,
                        'Status': result['status'],
                        'Score': result['score'],
                        'Message': result['message'],
                        'Issues': '\n'.join(result['issues']) if result['issues'] else '',
                        'Suggestions': '\n'.join(result['suggestions']) if result['suggestions'] else ''
                    })
                details_df = pd.DataFrame(details_data)
                details_df.to_excel(writer, sheet_name='Details', index=False)
                
                # 创建图表sheet
                self._create_charts(writer, data)
                
                # 设置列宽和格式
                self._format_worksheets(writer)
            
            logger.info(f"Enhanced Excel report exported to {output_path}")
            return True
        except Exception as e:
            logger.error(f"Error exporting enhanced Excel report: {str(e)}")
            return False
    
    def _create_charts(self, writer, data):
        """创建图表"""
        # 创建状态分布饼图
        plt.figure(figsize=(10, 6))
        status_counts = {
            'Healthy': data['summary']['healthy'],
            'Warning': data['summary']['warning'],
            'Critical': data['summary']['critical'],
            'Unknown': data['summary']['unknown']
        }
        plt.pie(status_counts.values(), labels=status_counts.keys(), autopct='%1.1f%%')
        plt.title('Resource Health Status Distribution')
        plt.savefig('temp_status_chart.png')
        plt.close()
        
        # 创建分数分布直方图
        plt.figure(figsize=(10, 6))
        scores = [result['score'] for result in data['details'].values()]
        sns.histplot(scores, bins=10)
        plt.title('Resource Health Score Distribution')
        plt.xlabel('Score')
        plt.ylabel('Count')
        plt.savefig('temp_score_chart.png')
        plt.close()
        
        # 将图表添加到Excel
        workbook = writer.book
        charts_sheet = workbook.create_sheet('Charts')
        
        # 添加饼图
        img = openpyxl.drawing.image.Image('temp_status_chart.png')
        charts_sheet.add_image(img, 'A1')
        
        # 添加直方图
        img = openpyxl.drawing.image.Image('temp_score_chart.png')
        charts_sheet.add_image(img, 'A20')
        
        # 删除临时文件
        os.remove('temp_status_chart.png')
        os.remove('temp_score_chart.png')
    
    def _format_worksheets(self, writer):
        """设置工作表格式"""
        for sheet_name in writer.sheets:
            worksheet = writer.sheets[sheet_name]
            
            # 设置列宽
            for idx, col in enumerate(worksheet.columns):
                max_length = max(
                    len(str(cell.value)) for cell in col
                )
                worksheet.column_dimensions[chr(65 + idx)].width = min(max_length + 2, 50)
            
            # 添加过滤器
            worksheet.auto_filter.ref = worksheet.dimensions
            
            # 冻结首行
            worksheet.freeze_panes = 'A2'
            
            # 设置样式
            header_font = openpyxl.styles.Font(bold=True)
            for cell in worksheet[1]:
                cell.font = header_font

class ProgressReportingFormatter(ReportFormatter):
    """带进度报告的报告格式化器装饰器"""
    
    def __init__(self, formatter: ReportFormatter):
        self.formatter = formatter
    
    def can_handle(self, format_type: str) -> bool:
        return self.formatter.can_handle(format_type)
    
    def format(self, data: Dict[str, Any], output_path: str) -> bool:
        try:
            print(f"开始导出{self.formatter.__class__.__name__}格式报告...")
            
            # 显示进度条
            with tqdm(total=100, desc="导出进度") as pbar:
                # 准备数据
                pbar.update(20)
                time.sleep(0.5)  # 模拟处理时间
                
                # 格式化数据
                pbar.update(30)
                time.sleep(0.5)  # 模拟处理时间
                
                # 写入文件
                pbar.update(30)
                time.sleep(0.5)  # 模拟处理时间
                
                # 完成
                pbar.update(20)
            
            result = self.formatter.format(data, output_path)
            
            if result:
                print(f"报告已成功导出到: {output_path}")
            else:
                print("报告导出失败")
            
            return result
        except Exception as e:
            logger.error(f"Error in progress reporting formatter: {str(e)}")
            return False

class ReportFormatterFactory:
    """报告格式化器工厂"""
    
    @staticmethod
    def create_formatter_chain(template_dir: str) -> ReportFormatter:
        """创建格式化器链"""
        # 创建基础格式化器实例
        yaml_formatter = YAMLFormatter()
        json_formatter = JSONFormatter()
        html_formatter = HTMLFormatter(template_dir)
        pdf_formatter = PDFFormatter(template_dir)
        markdown_formatter = MarkdownFormatter()
        excel_formatter = EnhancedExcelFormatter()
        csv_formatter = CSVFormatter()
        xml_formatter = XMLFormatter()
        console_formatter = ConsoleFormatter()
        junit_formatter = JUnitFormatter()
        jsonl_formatter = JSONLinesFormatter()
        asciidoc_formatter = AsciiDocFormatter()
        
        # 添加进度报告装饰器
        formatters = [
            yaml_formatter, json_formatter, html_formatter, pdf_formatter,
            markdown_formatter, excel_formatter, csv_formatter, xml_formatter,
            console_formatter, junit_formatter, jsonl_formatter, asciidoc_formatter
        ]
        
        # 构建职责链
        for i in range(len(formatters) - 1):
            formatters[i].set_next(formatters[i + 1])
        
        return formatters[0] 